package com.yupi.yuaicodemother.utils;

import cn.hutool.core.img.ImgUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import com.yupi.yuaicodemother.exception.BusinessException;
import com.yupi.yuaicodemother.exception.ErrorCode;
import io.github.bonigarcia.wdm.WebDriverManager;
import lombok.extern.slf4j.Slf4j;
import org.openqa.selenium.JavascriptExecutor;
import org.openqa.selenium.OutputType;
import org.openqa.selenium.TakesScreenshot;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeOptions;
import org.openqa.selenium.support.ui.WebDriverWait;

import java.io.File;
import java.time.Duration;
import java.util.UUID;

/**
 * 网页截图工具类
 * 使用懒加载模式初始化 ChromeDriver，避免静态初始化失败导致类无法加载
 */
@Slf4j
public class WebScreenshotUtils {

    private static volatile WebDriver webDriver;
    private static final Object lock = new Object();
    private static final int DEFAULT_WIDTH = 1600;
    private static final int DEFAULT_HEIGHT = 900;
    private static final int MAX_INIT_RETRIES = 3; // 最大初始化重试次数
    private static volatile boolean initializationFailed = false; // 标记初始化是否失败

    /**
     * 获取 WebDriver 实例（懒加载）
     * 使用 double-check locking 模式确保线程安全
     */
    private static WebDriver getWebDriver() {
        if (webDriver == null && !initializationFailed) {
            synchronized (lock) {
                if (webDriver == null && !initializationFailed) {
                    webDriver = initChromeDriverWithRetry(DEFAULT_WIDTH, DEFAULT_HEIGHT);
                    if (webDriver == null) {
                        initializationFailed = true;
                    }
                }
            }
        }
        if (webDriver == null) {
            throw new BusinessException(ErrorCode.SYSTEM_ERROR, "Chrome 浏览器驱动初始化失败，无法生成截图");
        }
        return webDriver;
    }

    /**
     * 带重试机制的 Chrome 浏览器驱动初始化
     */
    private static WebDriver initChromeDriverWithRetry(int width, int height) {
        for (int attempt = 1; attempt <= MAX_INIT_RETRIES; attempt++) {
            try {
                log.info("初始化 Chrome 浏览器驱动，尝试次数: {}/{}", attempt, MAX_INIT_RETRIES);
                WebDriver driver = initChromeDriver(width, height);
                log.info("Chrome 浏览器驱动初始化成功");
                return driver;
            } catch (Exception e) {
                log.warn("初始化 Chrome 浏览器驱动失败，尝试次数: {}/{}, 错误: {}", 
                        attempt, MAX_INIT_RETRIES, e.getMessage());
                if (attempt < MAX_INIT_RETRIES) {
                    try {
                        Thread.sleep(2000); // 重试前等待2秒
                    } catch (InterruptedException ie) {
                        Thread.currentThread().interrupt();
                        log.error("重试延迟被中断", ie);
                        break;
                    }
                } else {
                    log.error("初始化 Chrome 浏览器驱动失败，已达到最大重试次数", e);
                }
            }
        }
        return null;
    }

    /**
     * 初始化 Chrome 浏览器驱动
     */
    private static WebDriver initChromeDriver(int width, int height) {
        try {
            // 自动管理 ChromeDriver
            WebDriverManager.chromedriver().setup();
            // 配置 Chrome 选项
            ChromeOptions options = new ChromeOptions();
            // 无头模式
            options.addArguments("--headless");
            // 禁用GPU（在某些环境下避免问题）
            options.addArguments("--disable-gpu");
            // 禁用沙盒模式（Docker环境需要）
            options.addArguments("--no-sandbox");
            // 禁用开发者shm使用
            options.addArguments("--disable-dev-shm-usage");
            // 设置窗口大小
            options.addArguments(String.format("--window-size=%d,%d", width, height));
            // 禁用扩展
            options.addArguments("--disable-extensions");
            // 设置用户代理
            options.addArguments("--user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36");
            // 创建驱动
            WebDriver driver = new ChromeDriver(options);
            // 设置页面加载超时
            driver.manage().timeouts().pageLoadTimeout(Duration.ofSeconds(30));
            // 设置隐式等待
            driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(10));
            return driver;
        } catch (Exception e) {
            log.error("初始化 Chrome 浏览器驱动时发生异常", e);
            throw new BusinessException(ErrorCode.SYSTEM_ERROR, "初始化 Chrome 浏览器失败: " + e.getMessage());
        }
    }

    /**
     * 保存图片到文件
     */
    private static void saveImage(byte[] imageBytes, String imagePath) {
        try {
            FileUtil.writeBytes(imageBytes, imagePath);
        } catch (Exception e) {
            log.error("保存图片失败: {}", imagePath, e);
            throw new BusinessException(ErrorCode.SYSTEM_ERROR, "保存图片失败");
        }
    }

    /**
     * 压缩图片
     */
    private static void compressImage(String originalImagePath, String compressedImagePath) {
        // 压缩图片质量（0.1 = 10% 质量）
        final float COMPRESSION_QUALITY = 0.3f;
        try {
            ImgUtil.compress(
                    FileUtil.file(originalImagePath),
                    FileUtil.file(compressedImagePath),
                    COMPRESSION_QUALITY
            );
        } catch (Exception e) {
            log.error("压缩图片失败: {} -> {}", originalImagePath, compressedImagePath, e);
            throw new BusinessException(ErrorCode.SYSTEM_ERROR, "压缩图片失败");
        }
    }

    /**
     * 等待页面加载完成
     */
    private static void waitForPageLoad(WebDriver driver) {
        try {
            // 创建等待页面加载对象
            WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(10));
            // 等待 document.readyState 为complete
            wait.until(webDriver ->
                    ((JavascriptExecutor) webDriver).executeScript("return document.readyState")
                            .equals("complete")
            );
            // 额外等待一段时间，确保动态内容加载完成
            Thread.sleep(2000);
            log.info("页面加载完成");
        } catch (Exception e) {
            log.error("等待页面加载时出现异常，继续执行截图", e);
        }
    }

    /**
     * 生成网页截图
     *
     * @param webUrl 网页URL
     * @return 压缩后的截图文件路径，失败返回null
     */
    public static String saveWebPageScreenshot(String webUrl) {
        if (StrUtil.isBlank(webUrl)) {
            log.error("网页URL不能为空");
            return null;
        }
        
        WebDriver driver = null;
        try {
            // 懒加载获取 WebDriver
            driver = getWebDriver();
            
            // 创建临时目录
            String rootPath = System.getProperty("user.dir") + File.separator + "tmp" + File.separator + "screenshots"
                    + File.separator + UUID.randomUUID().toString().substring(0, 8);
            FileUtil.mkdir(rootPath);
            // 图片后缀
            final String IMAGE_SUFFIX = ".png";
            // 原始截图文件路径
            String imageSavePath = rootPath + File.separator + RandomUtil.randomNumbers(5) + IMAGE_SUFFIX;
            // 访问网页
            driver.get(webUrl);
            // 等待页面加载完成
            waitForPageLoad(driver);
            // 截图
            byte[] screenshotBytes = ((TakesScreenshot) driver).getScreenshotAs(OutputType.BYTES);
            // 保存原始图片
            saveImage(screenshotBytes, imageSavePath);
            log.info("原始截图保存成功: {}", imageSavePath);
            // 压缩图片
            final String COMPRESSION_SUFFIX = "_compressed.jpg";
            String compressedImagePath = rootPath + File.separator + RandomUtil.randomNumbers(5) + COMPRESSION_SUFFIX;
            compressImage(imageSavePath, compressedImagePath);
            log.info("压缩图片保存成功: {}", compressedImagePath);
            // 删除原始图片，只保留压缩图片
            FileUtil.del(imageSavePath);
            return compressedImagePath;
        } catch (BusinessException e) {
            // 业务异常（如初始化失败）直接抛出
            log.error("网页截图失败（业务异常）: {}", webUrl, e);
            throw e;
        } catch (Exception e) {
            log.error("网页截图失败: {}", webUrl, e);
            return null;
        }
    }
    
    /**
     * 关闭 WebDriver（用于应用关闭时清理资源）
     * 注意：这是一个工具类，不是 Spring Bean，需要在应用关闭时手动调用
     */
    public static void shutdown() {
        synchronized (lock) {
            if (webDriver != null) {
                try {
                    webDriver.quit();
                    log.info("Chrome 浏览器驱动已关闭");
                } catch (Exception e) {
                    log.error("关闭 Chrome 浏览器驱动时发生异常", e);
                } finally {
                    webDriver = null;
                    initializationFailed = false;
                }
            }
        }
    }
}